package base

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"gorm.io/gorm"
)

//DataFilter 数据过滤接口
type DataFilter interface {
	SetDB(string) error
	GetFilterColName() (string, error)
	SetAdditional(string, interface{})
	GetFilterKeys(pType string, userID int, flowType string) ([]int, error)
}

//DefaultFilter 默认的数据过滤
type DefaultFilter struct {
	db            *gorm.DB
	FilterColName string
}

func (f *DefaultFilter) SetDB(dbtp string) (err error) {
	if dbtp == "my" {
		f.db = MYDB
	} else if dbtp == "ch" {
		f.db = CHDB
	} else {
		err = fmt.Errorf("错误的dbtp:%s，dbtp只能为my或者ch", dbtp)
	}
	return
}

//GetFilterColName 获取要过滤的实体的字段名称
func (f *DefaultFilter) GetFilterColName() (string, error) {
	if f.FilterColName == "" {
		return "", errors.New("FilterColName不能为空！")
	}
	return f.FilterColName, nil
}

//SetAdditional 设置额外的属性
func (f *DefaultFilter) SetAdditional(name string, val interface{}) {

}

//GetFilterKeys 获取指定权限类型和id可以查看的数据键值
func (f *DefaultFilter) GetFilterKeys(pType string, userID int, flowType string) ([]int, error) {
	var sql string
	if pType == "3" {
		sql = fmt.Sprintf(`select "EMID" from "V_USER_DEPT" where "DPID" = (select "DPID" from "V_USER_DEPT" where "EMID"=%d)`, userID)
	} else if pType == "L" {
		sql = fmt.Sprintf(`select "EMID" from "V_USER_DEPT" where "PDID" = (select "PDID" from "V_USER_DEPT" where "EMID"=%d)`, userID)
	} else {
		return []int{userID}, nil
	}
	return execSQL(sql, f.db)
}

//WorkFolowFilter 流程的数据过滤
type WorkFolowFilter struct {
	db            *gorm.DB
	FilterColName string
	additionalMap map[string]interface{}
}

func (f *WorkFolowFilter) SetDB(dbtp string) (err error) {
	if dbtp == "my" {
		f.db = MYDB
	} else if dbtp == "ch" {
		f.db = CHDB
	} else {
		err = fmt.Errorf("错误的dbtp:%s，dbtp只能为my或者ch", dbtp)
	}
	return
}

//GetFilterColName 获取要过滤的实体的字段名称
func (f *WorkFolowFilter) GetFilterColName() (string, error) {
	if f.FilterColName == "" {
		return "", errors.New("FilterColName不能为空！")
	}
	return f.FilterColName, nil
}

//SetAdditional 设置额外的属性
func (f *WorkFolowFilter) SetAdditional(name string, val interface{}) {
	if f.additionalMap == nil {
		f.additionalMap = make(map[string]interface{})
	}
	f.additionalMap[name] = val
}

//GetFilterKeys 获取指定权限类型和id可以查看的数据键值
func (f *WorkFolowFilter) GetFilterKeys(pType string, userID int, flowType string) ([]int, error) {
	if f.db == nil {
		return nil, errors.New("db==nil,没有执行SetDB")
	}
	var sql string
	if flowType == "" {
		flowType = "all"
	}
	aper := f.additionalMap["appointer"]
	aperSteps := make([]string, 0, 5)
	uIDStr := strconv.Itoa(userID)
	if apMap, ok := aper.(map[int][]string); ok {
		for k, v := range apMap {
			if IsInSlice(v, uIDStr) {
				aperSteps = append(aperSteps, strconv.Itoa(k))
			}
		}
	}
	reco := f.additionalMap["recorder"]
	isReco := false
	if recoArr, ok := reco.([]string); ok {
		if recoArr != nil && IsInSlice(recoArr, uIDStr) {
			isReco = true
		}
	}
	managers := ""
	if f.additionalMap["manager"] != nil {
		managers = ToString(f.additionalMap["manager"])
	}
	isMg := false
	mgWfids := make([]string, 0, 3)
	if managers != "" {
		mArr := strings.Split(managers, ";")
		for _, m := range mArr {
			wfrls := strings.Split(m, ":")
			if len(wfrls) != 2 {
				return nil, fmt.Errorf("错误的manager附加属性%s，格式应该为wfid:roleid,roleid;wfid:roleid,roleid", managers)
			}
			if wfrls[0] == "" || wfrls[1] == "" {
				continue
			}
			sql = `select COUNT(*) from "t_UserRole" WHERE "UserId"=? AND "RoleId" IN (?)`
			row := MYDB.Raw(sql, userID, strings.Split(wfrls[1], ",")).Row()
			var count int
			row.Scan(&count)
			if count > 0 {
				isMg = true
				mgWfids = append(mgWfids, wfrls[0])
			}
		}
	}
	wfid := ToString(f.additionalMap["wfid"])
	if isMg {
		pType = "4"
		wfid = strings.Join(mgWfids, ",")
	}
	if len(aperSteps) == 0 && !isReco {
		if flowType == "apply" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID"=%d and "STEPID"=1`, userID)
		} else if flowType == "doing" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID"=%d and "STATE" in ('0','1') and "STEPID">1`, userID)
		} else if flowType == "done" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID"=%d and "STATE" = '2' and "STEPID">1 and "RUNID" in(select "ID" from "T_FLOW_RUN" where "STATE"='0')`, userID)
		} else if flowType == "closed" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP_HIS" where "EMID"=%d and "STATE" = '2' and "STEPID">1`, userID)
		} else if flowType == "finish" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID"=%d and "STATE" = '2' and "STEPID">1`, userID)
		} else if flowType == "aborted" {
			sql = fmt.Sprintf(`select b."RUNID" from "T_FLOW_RUN" a inner join "T_FLOW_RUN_STEP" b on a."ID"=b."RUNID" where "EMID"=%d and a."STATE" = '2' and "STEPID">1`, userID)
		} else if flowType == "firstdoing" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID"=%d and "STATE" in ('0','1') and "STEPID"=1`, userID)
		} else if flowType == "firstdone" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID"=%d and "STATE" = '2' and "STEPID"=1 and "RUNID" in(select "ID" from "T_FLOW_RUN" where "STATE"='0')`, userID)
		} else if flowType == "firstclosed" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP_HIS" where "EMID"=%d and "STATE" = '2' and "STEPID"=1`, userID)
		} else if flowType == "firstfinish" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID"=%d and "STATE" = '2' and "STEPID"=1`, userID)
		} else if flowType == "firstaborted" {
			sql = fmt.Sprintf(`select b."RUNID" from "T_FLOW_RUN" a inner join "T_FLOW_RUN_STEP" b on a."ID"=b."RUNID" where "EMID"=%d and a."STATE" = '2' and "STEPID"=1`, userID)
		} else if flowType == "manager" {
			if isMg {
				sql = fmt.Sprintf(`select "ID" from "T_FLOW_RUN" where "WFID" in (%s) and "STATE" in ('0','2')`, wfid)
			} else {
				sql = `select "ID" from "T_FLOW_RUN" where "WFID"=-1`
			}
		} else if flowType == "firstall" {
			if pType == "3" {
				sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID" in (select "ID" from "T_SysUser" where "OrganId" = (select "OrganId" from "T_SysUser" where "ID"=%d)) and "STEPID"=1`, userID)
			} else if pType == "1" {
				sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID"=%d and "STEPID"=1`, userID)
			} else {
				sql = fmt.Sprintf(`select "ID" from "T_FLOW_RUN" where "WFID" in (%s) and "STEP"=1`, wfid)
			}
		} else if pType == "3" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID" in (select "ID" from "T_SysUser" where "OrganId" = (select "OrganId" from "T_SysUser" where ID=%d))`, userID)
		} else if pType == "1" {
			sql = fmt.Sprintf(`select "RUNID" from "T_FLOW_RUN_STEP" where "EMID"=%d`, userID)
		} else {
			sql = fmt.Sprintf(`select "ID" from "T_FLOW_RUN" where "WFID" in (%s)`, wfid)
		}
	} else if isReco {
		sql = fmt.Sprintf(`select "ID" from "T_FLOW_RUN" where "WFID"=%s and "STAT" = '1'`, wfid)
	} else {
		stepStr := strings.Join(aperSteps, ",")
		if flowType == "doing" {
			sql = fmt.Sprintf(`select "ID" from "T_FLOW_RUN" where "WFID"=%s and "STEP" in (%s)`, wfid, stepStr)
		} else if flowType == "done" {
			sql = fmt.Sprintf(`select "ID" from "T_FLOW_RUN" where "WFID"=%s and "STEP" not in (%s)`, wfid, stepStr)
		} else {
			sql = fmt.Sprintf(`select "ID" from "T_FLOW_RUN" where "WFID" in (%s)`, wfid)
		}
	}
	return execSQL(sql, f.db)
}

func execSQL(sql string, db *gorm.DB) ([]int, error) {
	rows, err := db.Raw(sql).Rows()
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	acids := make([]int, 0, 10)
	for rows.Next() {
		var id int
		err = rows.Scan(&id)
		if err != nil {
			return nil, err
		}
		acids = append(acids, id)
	}
	return acids, nil
}
